#include <vector>
#include "pointlocator.h"
#include "locatorcell.h"

point_locator_t::point_locator_t()
{
}

point_locator_t::point_locator_t(std::vector<MAP_OBJECT> const & objs, double cell_size) 
	: grid_(grid_t<locator_cell_t, locator_cell_inserter>(cell_size))
{
	for(size_t i = 0; i < objs.size(); ++i)
	{
		locator_cell_inserter ins(objs[i].mobj_id);
		boost::function<void (locator_cell_t &, segment_t const &)> f = boost::ref(ins);
		grid_.visit(objs[i].polygon, f);
	}
	grid_.validate();
	make_centers_parent();
}
	
int point_locator_t::inside(point_t const & point) const
{
	if(!grid_.inside(point))
		return -1;

	locator_cell_t cell = grid_.cell_at(point);
    manhattan_line_t m_line(point, cell.center());
	boost::optional<segment_t const &> seg = cell.min_segment(m_line, VERT_PART);
	
	if(seg)
		return cell.get_parent(*seg);
	
	seg = cell.min_segment(m_line, HOR_PART);
	if(seg)
		return cell.get_parent(*seg);

	return cell.get_parent();
}

void point_locator_t::make_centers_parent()
{
	for (size_t i = 1; i < grid_.size(); ++i)
	{
		manhattan_line_t m_line(grid_[i].center(), grid_[i-1].center());
		boost::optional<segment_t const &> seg = grid_[i].min_segment(m_line, BASE_PART);
		if (seg)
			grid_[i].set_center_parent(grid_[i].get_parent(*seg));
		else
		{
			seg = grid_[i-1].min_segment(m_line, BASE_PART);
			if (seg)
			{
				grid_[i].set_center_parent(grid_[i-1].get_parent(*seg));
			} 
			else
			{
				grid_[i].set_center_parent(grid_[i-1].get_parent());
			}
		}
	}
}
